package org.zecontech.extraplus.datagen.levelgen;

import com.google.common.collect.ImmutableList;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.data.worldgen.features.FeatureUtils;
import net.minecraft.data.worldgen.placement.PlacementUtils;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.random.WeightedList;
import net.minecraft.util.valueproviders.UniformInt;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.world.level.levelgen.feature.configurations.FallenTreeConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.RandomPatchConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.SimpleBlockConfiguration;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize;
import net.minecraft.world.level.levelgen.feature.foliageplacers.SpruceFoliagePlacer;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider;
import net.minecraft.world.level.levelgen.feature.treedecorators.AttachedToLogsDecorator;
import net.minecraft.world.level.levelgen.feature.trunkplacers.StraightTrunkPlacer;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockMatchTest;
import net.minecraft.world.level.levelgen.structure.templatesystem.RuleTest;
import net.minecraft.world.level.levelgen.structure.templatesystem.TagMatchTest;
import net.neoforged.neoforge.registries.DeferredBlock;
import org.zecontech.extraplus.init.ModBlockTagKeys;
import org.zecontech.extraplus.init.ModBlocks;
import org.zecontech.extraplus.util.Helpers;

import java.util.List;

/**
 * 模组配置特征数据生成提供者
 */
public class ModConfiguredFeatureProvider {

    public static final ResourceKey<ConfiguredFeature<?, ?>> ORE_RUBY =
            register("ore_ruby");
    public static final ResourceKey<ConfiguredFeature<?, ?>> ORE_AMBER =
            register("ore_amber");
    public static final ResourceKey<ConfiguredFeature<?, ?>> PLANTAGO =
            register("plantago");
    public static final ResourceKey<ConfiguredFeature<?, ?>> ACHILLEA_WHITE =
            register("achillea_white");
    public static final ResourceKey<ConfiguredFeature<?, ?>> ANAGALLIS_YELLOW =
            register("anagallis_yellow");
    public static final ResourceKey<ConfiguredFeature<?, ?>> ANTIRRHINUM =
            register("antirrhinum");
    public static final ResourceKey<ConfiguredFeature<?, ?>> CAMPANULA_BLUE =
            register("campanula_blue");
    public static final ResourceKey<ConfiguredFeature<?, ?>> CENTAUREA =
            register("centaurea");
    public static final ResourceKey<ConfiguredFeature<?, ?>> DIGITALIS_BLUE =
            register("digitalis_blue");
    public static final ResourceKey<ConfiguredFeature<?, ?>> DIGITALIS_YELLOW =
            register("digitalis_yellow");
    public static final ResourceKey<ConfiguredFeature<?, ?>> DOSERA =
            register("dosera");
    public static final ResourceKey<ConfiguredFeature<?, ?>> IRIS =
            register("iris");
    public static final ResourceKey<ConfiguredFeature<?, ?>> LEONTOPODIUM_WHITE =
            register("leontopodium_white");
    public static final ResourceKey<ConfiguredFeature<?, ?>> LEUCANTHEMUM_WHITE =
            register("leucanthemum_white");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_AMANITA_GREEN =
            register("mushroom_amanita_green");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_BOLETUS =
            register("mushroom_boletus");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_CANTHARELLUS =
            register("mushroom_cantharellus");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_GALERINA =
            register("mushroom_galerina");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_GYROMITRA =
            register("mushroom_gyromitra");
    public static final ResourceKey<ConfiguredFeature<?, ?>> MUSHROOM_MACROLEPIOTA =
            register("mushroom_macrolepiota");
    public static final ResourceKey<ConfiguredFeature<?, ?>> PAPVER_RED =
            register("papver_red");
    public static final ResourceKey<ConfiguredFeature<?, ?>> TRIFOLIUM_RED =
            register("trifolium_red");
    public static final ResourceKey<ConfiguredFeature<?, ?>> TRIFOLIUM_WHITE =
            register("trifolium_white");
    public static final ResourceKey<ConfiguredFeature<?, ?>> WILLOW =
            register("willow");
    public static final ResourceKey<ConfiguredFeature<?, ?>> FALLEN_WILLOW_TREE =
            register("fallen_willow_tree");


    /**
     * 配置特征数据
     * @param context 模组配置内容
     */
    public static void configuredFeatures(BootstrapContext<ConfiguredFeature<?, ?>> context) {
        registerSimpleOre(context, ORE_RUBY, ModBlocks.RUBY_ORE.get(), 9);
        registerNetherOre(context, ORE_AMBER, ModBlocks.AMBER_ORE.get(), 9);
        registerHerb(context, PLANTAGO, ModBlocks.PLANTAGO);
        registerHerb(context, ACHILLEA_WHITE, ModBlocks.ACHILLEA_WHITE);
        registerHerb(context, ANAGALLIS_YELLOW, ModBlocks.ANAGALLIS_YELLOW);
        registerHerb(context, ANTIRRHINUM, ModBlocks.ANTIRRHINUM);
        registerHerb(context, CAMPANULA_BLUE, ModBlocks.CAMPANULA_BLUE);
        registerHerb(context, CENTAUREA, ModBlocks.CENTAUREA);
        registerHerb(context, DIGITALIS_BLUE, ModBlocks.DIGITALIS_BLUE);
        registerHerb(context, DIGITALIS_YELLOW, ModBlocks.DIGITALIS_YELLOW);
        registerHerb(context, DOSERA, ModBlocks.DOSERA);
        registerHerb(context, IRIS, ModBlocks.IRIS);
        registerHerb(context, LEONTOPODIUM_WHITE, ModBlocks.LEONTOPODIUM_WHITE);
        registerHerb(context, LEUCANTHEMUM_WHITE, ModBlocks.LEUCANTHEMUM_WHITE);
        registerHerb(context, MUSHROOM_AMANITA_GREEN, ModBlocks.MUSHROOM_AMANITA_GREEN);
        registerHerb(context, MUSHROOM_BOLETUS, ModBlocks.MUSHROOM_BOLETUS);
        registerHerb(context, MUSHROOM_CANTHARELLUS, ModBlocks.MUSHROOM_CANTHARELLUS);
        registerHerb(context, MUSHROOM_GALERINA, ModBlocks.MUSHROOM_GALERINA);
        registerHerb(context, MUSHROOM_GYROMITRA, ModBlocks.MUSHROOM_GYROMITRA);
        registerHerb(context, MUSHROOM_MACROLEPIOTA, ModBlocks.MUSHROOM_MACROLEPIOTA);
        registerHerb(context, PAPVER_RED, ModBlocks.PAPVER_RED);
        registerHerb(context, TRIFOLIUM_RED, ModBlocks.TRIFOLIUM_RED);
        registerHerb(context, TRIFOLIUM_WHITE, ModBlocks.TRIFOLIUM_WHITE);
        registerTree(context, WILLOW, FALLEN_WILLOW_TREE, ModBlocks.WILLOW_LOG.get(), ModBlocks.WILLOW_LEAVES.get());
    }

    /**
     * 注册树
     * @param context 模组配置内容
     * @param key 资源键
     * @param key2 资源键2
     * @param log 树干方块
     * @param leaves 树叶方块
     */
    public static void registerTree(BootstrapContext<ConfiguredFeature<?, ?>> context, ResourceKey<ConfiguredFeature<?, ?>> key, ResourceKey<ConfiguredFeature<?, ?>> key2, Block log, Block leaves) {
        createSpruceLikeTrees(context, key, log, leaves);
        createFallenTree(context, key2, log);
    }

    /**
     * 注册草药
     * @param context 模组配置内容
     * @param key 资源键
     * @param herbBlock 草药方块
     */
    public static void registerHerb(BootstrapContext<ConfiguredFeature<?, ?>> context, ResourceKey<ConfiguredFeature<?, ?>> key, DeferredBlock<Block> herbBlock) {
        FeatureUtils.register(context, key, Feature.FLOWER, grassPatch(new WeightedStateProvider(WeightedList.<BlockState>builder().add(herbBlock.get().defaultBlockState(), 2).build()), 32));
    }

    /**
     * 创建草丛配置特征数据
     * @param stateProvider 草丛方块
     * @param tries 草丛的分布大小
     * @return 草丛配置特征数据
     */
    private static RandomPatchConfiguration grassPatch(BlockStateProvider stateProvider, int tries) {
        return FeatureUtils.simpleRandomPatchConfiguration(tries, PlacementUtils.onlyWhenEmpty(Feature.SIMPLE_BLOCK, new SimpleBlockConfiguration(stateProvider)));
    }

    /**
     * 注册简单矿
     * @param context 模组配置内容
     * @param key 资源键
     * @param oreBlock 矿方块
     * @param spreadSize 矿的分布大小
     */
    public static void registerSimpleOre(BootstrapContext<ConfiguredFeature<?, ?>> context, ResourceKey<ConfiguredFeature<?, ?>> key, Block oreBlock, int spreadSize) {
        RuleTest tagMatchTest = new TagMatchTest(ModBlockTagKeys.ORE_REPLACEABLES);
        List<OreConfiguration.TargetBlockState> list = List.of(OreConfiguration.target(tagMatchTest, oreBlock.defaultBlockState()));
        FeatureUtils.register(context, key, Feature.ORE, new OreConfiguration(list, spreadSize));
    }

    /**
     * 注册下界矿
     * @param context 模组配置内容
     * @param key 键
     * @param oreBlock 矿方块
     * @param spreadSize 矿的分布大小
     */
    public static void registerNetherOre(BootstrapContext<ConfiguredFeature<?, ?>> context, ResourceKey<ConfiguredFeature<?, ?>> key, Block oreBlock, int spreadSize) {
        RuleTest tagMatchTest = new BlockMatchTest(Blocks.NETHERRACK);
        List<OreConfiguration.TargetBlockState> list = List.of(OreConfiguration.target(tagMatchTest, oreBlock.defaultBlockState()));
        FeatureUtils.register(context, key, Feature.ORE, new OreConfiguration(list, spreadSize));
    }

    /**
     * 注册新的资源键
     * @param name 名字
     * @return 资源键
     */
    private static ResourceKey<ConfiguredFeature<?, ?>> register(String name) {
        return ResourceKey.create(Registries.CONFIGURED_FEATURE, Helpers.identifier(name));
    }

    /**
     * 创建云杉式树
     * @param context 上下文
     * @param key 资源键
     * @param log 树干方块
     * @param leaves 树叶方块
     */
    private static void createSpruceLikeTrees(BootstrapContext<ConfiguredFeature<?, ?>> context,
                                              ResourceKey<ConfiguredFeature<?, ?>> key, Block log, Block leaves) {
        FeatureUtils.register(
                context,
                key,
                Feature.TREE,
                new TreeConfiguration.TreeConfigurationBuilder(
                        BlockStateProvider.simple(log),
                        new StraightTrunkPlacer(5, 2, 1),
                        BlockStateProvider.simple(leaves),
                        new SpruceFoliagePlacer(UniformInt.of(2, 3), UniformInt.of(0, 2), UniformInt.of(1, 2)),
                        new TwoLayersFeatureSize(2, 0, 2)
                )
                        .ignoreVines()
                        .build()
        );
    }

    /**
     * 创建倒塌的树木
     * @param block 树干方块
     * @return 倒塌的树木
     */
    private static void createFallenTree(BootstrapContext<ConfiguredFeature<?, ?>> context,
                                         ResourceKey<ConfiguredFeature<?, ?>> key, Block block) {
        FeatureUtils.register(context, key, Feature.FALLEN_TREE, createFallenTrees(block, 6, 10).build());
    }

    /**
     * 创建倒塌的树木
     * @param logBlock 原木方块
     * @param minLength 最小长度
     * @param maxLength 最大长度
     * @return 倒塌的树木
     */
    private static FallenTreeConfiguration.FallenTreeConfigurationBuilder createFallenTrees(Block logBlock, int minLength, int maxLength) {
        return new FallenTreeConfiguration.FallenTreeConfigurationBuilder(BlockStateProvider.simple(logBlock), UniformInt.of(minLength, maxLength))
                .logDecorators(
                        ImmutableList.of(
                                new AttachedToLogsDecorator(
                                        0.1F,
                                        new WeightedStateProvider(
                                                WeightedList.<BlockState>builder()
                                                        .add(Blocks.RED_MUSHROOM.defaultBlockState(), 2)
                                                        .add(Blocks.BROWN_MUSHROOM.defaultBlockState(), 1)
                                        ),
                                        List.of(Direction.UP)
                                )
                        )
                );
    }
}
